package com.sheep.secret.filter;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Enumeration;
import java.util.HashMap;

import java.util.Map;
import java.util.UUID;

@Slf4j
@WebFilter(filterName = "myFilter", urlPatterns = "/*")
public class MyFilter implements Filter {

    private static Gson GSON = new GsonBuilder().disableHtmlEscaping().create();

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        log.info("enter RestFilter init method");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) servletRequest;
        HttpServletResponse resp = (HttpServletResponse) servletResponse;
        Map<String, Object> map = new HashMap<>();
        try {
            // HttpServletRequest 请求中的 body 内容仅能调用 request.getInputStream(),request.getReader()和request.getParameter("key")方法读取一次
            HttpServletRequest requestWrapper = new RepeatedlyReadRequestWrapper(req);
            RepeatedlyReadResponseWrapper responseWrapper = new RepeatedlyReadResponseWrapper(resp);

            String sessionId = UUID.randomUUID().toString();
            MDC.put("sessionId", sessionId);

            // Get request URL.
            map.put("URL", req.getRequestURL());
            map.put("Method", req.getMethod());
            map.put("Protocol", req.getProtocol());

            // 获取POST application/x-www-form-urlencoded方式或GET方式请求参数信息
            Map<String, String> parameterMaps = new HashMap<>();
            Enumeration<String> parametersIterator = req.getParameterNames();
            while (parametersIterator.hasMoreElements()) {
                String key = parametersIterator.nextElement();
                parameterMaps.put(key, req.getParameter(key));
            }
            // 获取POST application/json 中的参数信息
            map.put("parameters", parameterMaps);

            // 获取POST application/json方式请求参数信息
            if ("POST".equalsIgnoreCase(req.getMethod())) {
                if (req.getContentType().contains("application/json")) {
                    int len = req.getContentLength();
                    char[] buf = new char[len];
                    int bufcount = requestWrapper.getReader().read(buf);
                    if (len > 0 && bufcount <= len) {
                        String line = String.copyValueOf(buf).substring(0, bufcount);
                        if (line.contains("fileBase") || line.contains("filebase") || line.contains("base64")) {
                            log.info("{} 接口请求报文包含文件信息", req.getRequestURI());
                        } else {
                            log.info("{} 接口请求报文:{}", req.getRequestURI(), line);
                        }
                    }
                }
            }

            try {
                log.info("{} 接口请求头:{}", req.getRequestURI(), GSON.toJson(map));
            } catch (Exception e) {
                e.printStackTrace();
            }
            long startTime = System.currentTimeMillis();
            filterChain.doFilter(requestWrapper, responseWrapper);
            long endTime = System.currentTimeMillis();
            if (responseWrapper.getContent().contains("fileBase") || responseWrapper.getContent().contains("filebase") || responseWrapper.getContent().contains("base64")) {
                log.info("{} 接口响应码:{},响应时间:{}ms,响应报文包含文件信息", req.getRequestURI(), responseWrapper.getStatus(), endTime - startTime);
            } else {
                log.info("{} 接口响应码:{},响应时间:{}ms,响应报文:{}", req.getRequestURI(), responseWrapper.getStatus(), endTime - startTime, responseWrapper.getContent());
            }
            servletResponse.getOutputStream().write(responseWrapper.getContent().getBytes(StandardCharsets.UTF_8));
        } catch (Exception e) {
            log.error("RestFilter处理入参异常", e);
            ((HttpServletResponse) servletResponse).setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
        }
    }

    @Override
    public void destroy() {
        log.info("enter RestFilter destroy method");
    }

}
